package codebreaker.servidor;

import codebreaker.commom.Jogador;
import codebreaker.protocolo.Constantes;
import codebreaker.protocolo.Pacote;

/**
 * Nucleo do servidor do jogo Code Breaker. 
 * Contem a lista dos jogadores online, intermedia broadcast e
 * troca de mensagens entre eles
 *
 * @author Rodrigo
 */
public class Nucleo {
    
    /**
     * Porta base de conexao. O primeiro jogador se
     * conectara na porta base, o segundo, na porta base +1,
     * e assim por diante. Esta faixa de portas deve estar
     * reservada para uso deste aplicativo
     */
    public static final int PORTA_BASE = 10000;
    
    private JogadorListener jogadores[] = new JogadorListener[Constantes.MAXIMO_JOGADORES];
    private int numero;
    
    /**
     * Cria uma instancia do nucleo de controle do servidor
     * Code Breaker, com nenhum jogador online(servidor vazio)
     */
    public Nucleo() {
	
	for (int c = 0; c < Constantes.MAXIMO_JOGADORES; c++) {
	    jogadores[c] = null;
	}
	numero = 0;
    }
    
    /**
     * Adiciona jogador ao sistema
     * @param nome Nome do jogador
     * @return porta de acesso do socket
     */
    synchronized public int adicionarJogador(String nome) {
	
	if (numero == Constantes.MAXIMO_JOGADORES)
	    return -1;
	
	/* Cria objeto jogador e associa id */
	Jogador jogador = new Jogador(nome);	
	
	/* Encontra ID para jogador */
	for (byte c = 0; c < Constantes.MAXIMO_JOGADORES; c++) {
	    /* encontra id vazio */
	    if (jogadores[c] == null) {		
		jogador.setId(c);
	    }
	}
	numero++;
	
	/* Cria objeto para escutar jogador, na porta */
	int porta = PORTA_BASE + jogador.getId();
	JogadorListener jogadorListener =
		new JogadorListener(jogador, porta);
	
	/* adiciona ao vetor */
	jogadores[jogador.getId()] = jogadorListener;
	
	/* Cria e inicia thread para escutar jogador */
	Thread thread = new Thread(jogadorListener);
	thread.start();
	
	return porta;
    }
    
    /**
     * Remove jogador do sistema
     * @param ID do jogador
     */
    public void removerJogador(byte id) {
	
	/* remove do conjunto */
	jogadores[id] = null;
    }
    
    /**
     * Retorna numero de jogadores online
     * @return Numero de jogadores
     */
    public int numeroJogadores() {
	return numero;
    }
    
    /**
     * Verifica se nome existe no sistema
     * @param nome Nome a ser buscado
     * @return Verdadeiro se nome existe
     */
    public boolean nomeExiste(String nome) {
	
	for (int c = 0; c < Constantes.MAXIMO_JOGADORES; c++) {
	    
	    if (jogadores[c] != null &&
		    jogadores[c].getJogador().getNome().equalsIgnoreCase(nome))
		return true;
	}
	
	return false;
    }
    
    /**
     * Envia pacote para todos os clientes
     * @param pacote Pacote
     */
    public void broadcast(Jogador jogador, Pacote pacote) {
	for (byte c = 0; c < Constantes.MAXIMO_JOGADORES; c++) {
	    
	    if (jogadores[c] != null && !jogadores[c].getJogador().equals(jogador))
		jogadores[c].enviar(pacote);
	}
    }
    
    /**
     * Envia um pacote para um jogador
     * @param id ID do jogador
     * @param pacote Pacote a ser enviado
     */
    public void enviar(byte id, Pacote pacote) {
	if (jogadores[id] != null)
	    jogadores[id].enviar(pacote);
    }
    
    
    /**
     * Retorna jogador
     * @param id ID do jogador
     * @return Jogador ou nulo, se nao existe
     */
    public Jogador getJogador(byte id) {
	return jogadores[id].getJogador();
    }    
    
    /**
     * Retorna lista de jogadores no servidor
     * @return Lista de jogadores
     */
   public java.util.List getJogadores() {
	java.util.List lista = new java.util.LinkedList();
	
	for (byte c = 0; c < Constantes.MAXIMO_JOGADORES; c++) {
	    if (jogadores[c] != null)
		lista.add(jogadores[c].getJogador());
	}	
	return lista;
    }
    
    /**
     * Retorna nome jogador
     * @param id ID do jogador
     * @return Nome do jogador ou nulo, se nao existe
     */
    public String getNome(byte id) {
	if (jogadores[id] != null)
	    return jogadores[id].getJogador().getNome();
	else
	    return null;
    }
}
